﻿using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using CliCpp.Donet.Models;

namespace CliCpp.Donet.Utils;

public class Log
{
    private readonly ConcurrentDictionary<string, string> _concurrentDictionary = new();

    public static Log Instance { get; set; }

    public string GetCallerFileName(string callerFilePath)
    {
        if (string.IsNullOrEmpty(callerFilePath)) return string.Empty;
        return _concurrentDictionary.GetOrAdd(callerFilePath, filePath => Path.GetFileName(filePath));
    }

    public string GetCallerMethodName(string callerFilePath, string callerMemberName)
    {
        var fileName = GetCallerFileName(callerFilePath);
        return $"{fileName}::{callerMemberName}";
    }

    public void Error(string message, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_ERROR, message, callerMemberName, GetCallerFileName(callerFilePath),
            callerLineNumber);
    }

    public void Error(string message, LogTransInfo logTransInfo, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_ERROR, message, callerMemberName,
            $"|<{logTransInfo.TransInfo}>|{GetCallerFileName(callerFilePath)}",
            callerLineNumber);
    }

    public void Info(string message, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_INFO, message, callerMemberName, GetCallerFileName(callerFilePath),
            callerLineNumber);
    }

    public void Debug(string message, LogTransInfo logTransInfo = default,
        [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_INFO, message, callerMemberName,
            $"|<{logTransInfo.TransInfo}>|{GetCallerFileName(callerFilePath)}", callerLineNumber);
    }

    public void Info(string message, LogTransInfo logTransInfo, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_INFO, message, callerMemberName,
            $"|<{logTransInfo.TransInfo}>|{GetCallerFileName(callerFilePath)}", callerLineNumber);
    }

    public void Warn(string message, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_WARN, message, callerMemberName, GetCallerFileName(callerFilePath),
            callerLineNumber);
    }

    public void Warn(string message, LogTransInfo logTransInfo, [CallerMemberName] string callerMemberName = null,
        [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1)
    {
        WriteLog(ELoggingType.LOGGING_WARN, message, callerMemberName,
            $"|<{logTransInfo.TransInfo}>|{GetCallerFileName(callerFilePath)}", callerLineNumber);
    }

    private void WriteLog(ELoggingType loggingType, string message, string callerMemberName, string callerFileName,
        int callerLineNumber)
    {
        var threadId = Thread.CurrentThread.ManagedThreadId;
        var messageToWrite = $"[{threadId}] {message}";
        Console.WriteLine($"{loggingType},{callerFileName}::{callerMemberName}:{callerLineNumber}，{messageToWrite}");
    }

    private enum ELoggingType
    {
        LOGGING_TRACE = 0,
        LOGGING_DEBUG = 1,
        LOGGING_INFO = 2,
        LOGGING_WARN = 3,
        LOGGING_ERROR = 4
    }
}